﻿using SuperFrame.Charts.Modes;
using Microsoft.Expression.Shapes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SuperFrame.Charts
{
    public class HumidityControl : Viewbox
    {
        private delegate void RefreshDashBoardValue(double value);
        public HumidityControl()
            : base()
        {
            this.Loaded += HumidityControl_Loaded;
        }
        void HumidityControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_isLoaded)//加一个属性判断 防止重复加载
            {
                this.Stretch = Stretch.Uniform;
                rootPanel = new Canvas();
                rootPanel.Width = (InnerRadius + ArcThickness) * 2;
                rootPanel.Height = (InnerRadius + ArcThickness) * 1.3;
                this.Child = rootPanel;
                DrawingControl();
                this.Loaded -= HumidityControl_Loaded;
            }
        }


        #region Property

        private Canvas rootPanel = null;//面板容器

        private bool _isLoaded = false;
        /// <summary>
        /// 刻度线长度
        /// </summary>
        public double LittleScaleSize
        {
            get { return InnerRadius * 0.05; }
        }
        /// <summary>
        /// 刻度线长度
        /// </summary>
        public double BigScaleSize
        {
            get { return InnerRadius * 0.1; }
        }

        /// <summary>
        /// 指针中心点颜色
        /// </summary>
        private Brush centerColor = Brushes.Orange;
        /// <summary>
        /// 指针中心点颜色
        /// </summary>
        public Brush CenterColor
        {
            get { return centerColor; }
            set { centerColor = value; }
        }

        /// <summary>
        /// 中心点半径
        /// </summary>
        public double CenterRadius
        {
            get { return InnerRadius * 0.1; }
        }

        /// <summary>
        /// 指针颜色
        /// </summary>
        private Brush pointColor = Brushes.DarkGreen;
        /// <summary>
        /// 指针颜色
        /// </summary>
        public Brush PointColor
        {
            get { return pointColor; }
            set { pointColor = value; }
        }

        /// <summary>
        /// 小刻度线颜色
        /// </summary>
        private Brush littleScaleColor = Brushes.White;
        /// <summary>
        /// 小刻度线颜色
        /// </summary>
        public Brush LittleScaleColor
        {
            get { return littleScaleColor; }
            set { littleScaleColor = value; }
        }

        /// <summary>
        /// 大刻度线颜色
        /// </summary>
        private Brush bigScaleColor = Brushes.White;
        /// <summary>
        /// 大刻度线颜色
        /// </summary>
        public Brush BigScaleColor
        {
            get { return bigScaleColor; }
            set { bigScaleColor = value; }
        }


        private Brush outerColor = Brushes.Gray;
        /// <summary>
        /// 外圆背景
        /// </summary>
        public Brush OuterColor
        {
            get { return outerColor; }
            set { outerColor = value; }
        }


        private Brush innerColor = Brushes.Orange;
        /// <summary>
        /// 内圆背景
        /// </summary>
        public Brush InnerColor
        {
            get { return innerColor; }
            set { innerColor = value; }
        }


        private double minValue = 0;
        /// <summary>
        /// 起始刻度
        /// </summary>
        public double MinValue
        {
            get { return minValue; }
            set { minValue = value; }
        }


        private double maxValue = 100;
        /// <summary>
        /// 最大刻度
        /// </summary>
        public double MaxValue
        {
            get { return maxValue; }
            set { maxValue = value; }
        }


        private double uintValue_Little = 1;
        /// <summary>
        /// 刻度尺单位（表示N个单位刻度画一条小刻度线）
        /// </summary>
        public double UintValue_Little
        {
            get { return uintValue_Little; }
            set { uintValue_Little = value; }
        }


        private int unitValue_Big = 10;
        /// <summary>
        /// 表示N个小刻度刻度描一条大刻度线
        /// </summary>
        public int UnitValue_Big
        {
            get { return unitValue_Big; }
            set { unitValue_Big = value; }
        }


        private double startAngel = 0;
        /// <summary>
        /// 起始角度
        /// </summary>
        public double StartAngel
        {
            get { return startAngel; }
            set
            {
                if (value >= 0)
                    startAngel = value;
                else
                    throw new Exception("起始角度不能小于0°!");
            }
        }

        private double endAngel = 360;
        /// <summary>
        /// 结束角度
        /// </summary>
        public double EndAngel
        {
            get { return endAngel; }
            set
            {
                if (value <= 360)
                    endAngel = value;
                else
                    throw new Exception("起始角度不能大于360°!");
            }
        }


        private double innerRadius = 50;
        /// <summary>
        /// 内圆半径
        /// </summary>
        public double InnerRadius
        {
            get { return innerRadius; }
            set { innerRadius = value; }
        }

        private double lableFontSize = -1;
        /// <summary>
        /// 刻度标签字号
        /// </summary>
        public double LableFontSize
        {
            get
            {
                if (lableFontSize == -1)
                    return InnerRadius * 0.1 * (Math.Abs(EndAngel - StartAngel) / 360) / (Math.Abs(MaxValue - MinValue) / 100);
                return lableFontSize;
            }
            set
            {
                try
                {
                    lableFontSize = value;
                }
                catch
                {
                    lableFontSize = -1;
                }
            }
        }


        private Brush lableForeGround = Brushes.Black;
        /// <summary>
        /// 刻度标签颜色
        /// </summary>
        public Brush LableForeGround
        {
            get { return lableForeGround; }
            set { lableForeGround = value; }
        }

        /// <summary>
        /// 指针方向
        /// </summary>
        public double Ctype
        {
            get { return StartAngel > EndAngel ? -1 : 1; }
        }


        /// <summary>
        /// 标题
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(HumidityControl), new PropertyMetadata("温度"));



        /// <summary>
        /// 单位
        /// </summary>
        public string Unit
        {
            get { return (string)GetValue(UnitProperty); }
            set { SetValue(UnitProperty, value); }
        }
        public static readonly DependencyProperty UnitProperty = DependencyProperty.Register("Unit", typeof(string), typeof(HumidityControl), new PropertyMetadata("℃"));



        //private double cValue = 0;
        /// <summary>
        /// 当前值
        /// </summary>
        public double CurrentValue
        {
            get { return (double)GetValue(CurrentValueProperty); }
            set
            {
                SetValue(CurrentValueProperty, value);
            }
        }

        public static readonly DependencyProperty CurrentValueProperty =
            DependencyProperty.Register("CurrentValue", typeof(double), typeof(HumidityControl), new PropertyMetadata(0.00, new PropertyChangedCallback(CurrentValuePropertychanged)));

        private static void CurrentValuePropertychanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            HumidityControl basecontrol = obj as HumidityControl;
            if (basecontrol != null)
                basecontrol.Dispatcher.Invoke(new RefreshDashBoardValue(basecontrol.RefreshValue), double.Parse(e.NewValue.ToString()));
        }

        public List<IntervalMode> IntervalList
        {
            get { return (List<IntervalMode>)GetValue(IntervalListProperty); }
            set { SetValue(IntervalListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IntervalList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IntervalListProperty =
            DependencyProperty.Register("IntervalList", typeof(List<IntervalMode>), typeof(HumidityControl), new PropertyMetadata(null));


        private double arcThickness = -1;
        /// <summary>
        /// 圆环弧宽
        /// </summary>
        public double ArcThickness
        {
            get
            {
                if (arcThickness == -1)
                    return InnerRadius * 0.1;
                return arcThickness;
            }
            set
            {
                try
                {
                    arcThickness = value;
                }
                catch { }
            }
        }

        /// <summary>
        /// 内部计算使用
        /// </summary>
        private double TempValue
        {
            get
            {
                double value = InnerRadius - ArcThickness;
                switch (ScalePosition)
                {
                    case ScalePosition.InnerArcOutSide:
                        value = InnerRadius - ArcThickness - ArcThickness * 0.2;
                        break;
                    case ScalePosition.InnerArcIn:
                        value = InnerRadius - ArcThickness;
                        break;
                    case ScalePosition.OuterArcOutSide:
                        value = InnerRadius + ArcThickness * 0.3;
                        break;
                }
                return value;
            }
        }
        /// <summary>
        /// 零点偏移量
        /// </summary>
        public double OffsetAngle = -180;

        private bool isShowOuterArc = false;
        /// <summary>
        /// 是否显现外弧
        /// </summary>
        public bool IsShowOuterArc
        {
            get { return isShowOuterArc; }
            set { isShowOuterArc = value; }
        }

        private ScalePosition scalePosition;
        /// <summary>
        /// 刻度线在外圆上 true(外圆) /false(内yuan)
        /// </summary>
        public ScalePosition ScalePosition
        {
            get { return scalePosition; }
            set { scalePosition = value; }
        }

        Path Cpoint = null;//指针

        public bool IsShowValue { get; set; }
        #endregion

        #region Method
        /// <summary>
        /// 根据当前值 刷新指针
        /// </summary>
        /// <param name="value"></param>
        private void RefreshValue(double value)
        {
            try
            {
                Brush colorBrush = CenterColor;
                if (IntervalList != null && IntervalList.Count > 0) //根据值判断指针的颜色
                {
                    for (int i = 1; i < IntervalList.Count; i++)
                    {
                        if (IntervalList[i - 1].Value <= value && IntervalList[i].Value >= value)
                        {
                            colorBrush = IntervalList[i].ColorValue;
                        }
                    }
                }
                RotateTransform rotateTransform = Cpoint.RenderTransform as RotateTransform;
                if (rotateTransform != null)
                {
                    DoubleAnimation da = new DoubleAnimation();
                    da.Duration = new Duration(TimeSpan.FromSeconds(1));
                    double angelValue = GetUnitAngel() * (value - MinValue);
                    da.To = angelValue;
                    rotateTransform.BeginAnimation(RotateTransform.AngleProperty, da);
                }
                Cpoint.Fill = colorBrush;
            }
            catch (Exception)
            {

               // throw;
            }
        }
        /// <summary>
        /// 绘制控件
        /// </summary>
        public void DrawingControl()
        {
            ClearControls();
            CalculateCriticalPoint();//计算临界点
            if (IsShowOuterArc)//外圆弧
            {
                DrawingOuterArc();
            }
            DrawingInnerArc();//画内弧
            DrawingScale();//画刻度
            DrawingCenterPoint();//画指针
            switch (ScalePosition)//画刻度线所在的弧
            {
                case ScalePosition.InnerArcOutSide:
                case ScalePosition.OuterArcOutSide:
                    DrawingScaleArcLine();
                    break;
                case ScalePosition.InnerArcIn:
                    break;
            }
            if (IsShowValue) AddTitle();
        }

        private void AddTitle()
        {
            StackPanel sp = new StackPanel() { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center };
            TextBlock tbName = new TextBlock() { Text = Title, FontSize = 0.1 * InnerRadius, Foreground = LableForeGround,Margin=new Thickness(0,15,0,0) };
            TextBlock tbValue = new TextBlock() { FontSize = 0.1 * InnerRadius, Foreground = LableForeGround, Margin = new Thickness(0, 15, 0, 0) };
            tbValue.SetBinding(TextBlock.TextProperty, new Binding("CurrentValue") { Source=this});
            TextBlock tbPercent = new TextBlock() { Text = Unit, FontSize = 0.1 * InnerRadius, Foreground = LableForeGround, Margin = new Thickness(0, 15, 0, 0) };
            sp.Children.Add(tbName);
            sp.Children.Add(tbValue);
            sp.Children.Add(tbPercent);
            sp.SetValue(Canvas.TopProperty, InnerRadius * 1.2);
            sp.SetValue(Canvas.LeftProperty, InnerRadius- Tools.GetStrFontWidth(Title)/2);
            rootPanel.Children.Add(sp);
        }

        #region 绘制界面元素的方法
        /// <summary>
        /// 绘制刻度线
        /// </summary>
        private void DrawingScale()
        {
            double Sa = StartAngel + OffsetAngle - 90;// (StartAngel - 270);
            double scalecount = GetScaleCount();
            int start = 0;
            while (start < scalecount + 1)
            {
                double angelValue = GetUnitAngel() * start * Ctype;
                Point startPoint = GetScaleLineStartPoint(Sa + angelValue);
                Line sLine = new Line();
                sLine.X1 = startPoint.X;
                sLine.Y1 = startPoint.Y;
                sLine.StrokeThickness = 2;
                Point endPoint;
                if (start % (UnitValue_Big * UintValue_Little) == 0)
                {
                    endPoint = GetScaleLineEndPoint(Sa + angelValue, BigScaleSize);
                    sLine.Stroke = BigScaleColor;
                    sLine.StrokeThickness = 0.15 * BigScaleSize;
                    if (!(start == scalecount && angelValue % 360 == 0)) //最后一枚标签位置如果和起始标签重合则不绘制
                    {
                        Point labEndPoint = GetScaleLineEndPoint(Sa + angelValue, BigScaleSize, true);
                        Label lab = new Label();
                        lab.Foreground = LableForeGround;
                        lab.Content = (MinValue + start).ToString();
                        lab.FontSize = LableFontSize;
                        double CX = labEndPoint.X;
                        double CY = labEndPoint.Y;
                        if (Math.Abs(CY - GetCenterPoint().Y) < 0.05)
                        {
                            if (CX > GetCenterPoint().X)
                            {
                                CX = CX - lab.Content.ToString().Length * LableFontSize;
                            }

                            CY = CY - LableFontSize / 2;
                        }
                        else if (Math.Abs(CX - GetCenterPoint().X) < 0.05)
                        {
                            if (CY > GetCenterPoint().Y)
                            {
                                CY = CY - LableFontSize;
                            }
                            CX = CX - lab.Content.ToString().Length * LableFontSize / 2;
                        }
                        else
                        {
                            CY = CY - LableFontSize / 2;
                            if (CX > GetCenterPoint().X)
                            {
                                CX = CX - lab.Content.ToString().Length * LableFontSize;
                            }
                        }
                        Canvas.SetLeft(lab, CX);
                        Canvas.SetTop(lab, CY);
                        rootPanel.Children.Add(lab);
                    }
                    sLine.X2 = endPoint.X;
                    sLine.Y2 = endPoint.Y;
                    rootPanel.Children.Add(sLine);
                }
                else if (start % UintValue_Little == 0)
                {
                    endPoint = GetScaleLineEndPoint(Sa + angelValue, LittleScaleSize);
                    sLine.Stroke = LittleScaleColor;
                    sLine.StrokeThickness = 0.15 * LittleScaleSize;
                    sLine.X2 = endPoint.X;
                    sLine.Y2 = endPoint.Y;
                    rootPanel.Children.Add(sLine);
                }
                start++;
            }
        }

        /// <summary>
        /// 绘制表盘指针
        /// </summary>
        private void DrawingCenterPoint()
        {
            double Sa = StartAngel + OffsetAngle - 90;// (StartAngel - 270);
            Cpoint = new Path();
            Cpoint.Fill = PointColor;
            Point startPoint = GetScaleLinePoint(Sa - 15, CenterRadius);
            Point point3 = GetScaleLinePoint(Sa - 195, CenterRadius);
            Point point4 = GetScaleLinePoint(Sa - 345, CenterRadius);
            Point point2 = GetScaleLinePoint(Sa, TempValue * 0.6);
            Cpoint.Data = new PathGeometry(new List<PathFigure>()
            {
                new PathFigure()
                {
                   StartPoint=startPoint,
                   Segments=new PathSegmentCollection()
                   {
                       new ArcSegment(point3,new Size(CenterRadius,CenterRadius),0,false,SweepDirection.Counterclockwise,true),
                       new ArcSegment(point4,new Size(CenterRadius,CenterRadius),0,false,SweepDirection.Counterclockwise,true),
                       new LineSegment(point2,false),
                       new LineSegment(startPoint,false)
                   },
                   IsClosed=true
                }
            });

            RotateTransform rtf = new RotateTransform();
            rtf.Angle = 0d;
            rtf.CenterX = GetCenterPoint().X;
            rtf.CenterY = GetCenterPoint().Y;
            Cpoint.RenderTransform = rtf;
            rootPanel.Children.Add(Cpoint);
        }

        /// <summary>
        /// 清理面板
        /// </summary>
        public void ClearControls()
        {
            rootPanel.Children.Clear();
        }
        /// <summary>
        /// 绘制内圆弧
        /// </summary>
        private void DrawingInnerArc()
        {
            if (IntervalList != null && IntervalList.Count > 0)
            {
                double Sa = StartAngel + OffsetAngle;
                double scalecount = GetScaleCount();//总刻度
                double tatolAngel = EndAngel - StartAngel;
                double unitAngel = tatolAngel / scalecount;
                double end = -180;
                for (int i = 1; i < IntervalList.Count; i++)
                {
                    end = Sa + unitAngel * (IntervalList[i].Value - IntervalList[i - 1].Value);
                    Arc innerArc = new Arc();
                    innerArc.Width = InnerRadius * 2;
                    innerArc.Height = InnerRadius * 2;
                    innerArc.ArcThickness = ArcThickness;
                    innerArc.Stretch = Stretch.None;
                    innerArc.Fill = IntervalList[i].ColorValue;
                    innerArc.StartAngle = Sa;
                    innerArc.EndAngle = end;
                    Canvas.SetLeft(innerArc, GetCenterPoint().X - InnerRadius);
                    Canvas.SetTop(innerArc, GetCenterPoint().Y - InnerRadius);
                    rootPanel.Children.Add(innerArc);
                    Sa = end;
                }
            }
            else
            {
                Arc innerArc = new Arc();
                innerArc.Width = InnerRadius * 2;
                innerArc.Height = InnerRadius * 2;
                innerArc.ArcThickness = ArcThickness;
                innerArc.Stretch = Stretch.None;
                double Sa = StartAngel + OffsetAngle;
                double Ea = EndAngel + OffsetAngle;
                if (Sa > Ea)
                {
                    innerArc.StartAngle = Ea;
                    innerArc.EndAngle = Sa;
                }
                else
                {
                    innerArc.StartAngle = Sa;
                    innerArc.EndAngle = Ea;
                }
                innerArc.StrokeThickness = 0;
                innerArc.Fill = InnerColor;
                Canvas.SetLeft(innerArc, GetCenterPoint().X - InnerRadius);
                Canvas.SetTop(innerArc, GetCenterPoint().Y - InnerRadius);
                rootPanel.Children.Add(innerArc);
            }
        }

        /// <summary>
        /// 绘制外圆弧
        /// </summary>
        private void DrawingOuterArc()
        {
            Arc outerArc = new Arc();
            //圆弧大小根据当前设定的内圆半径而定
            outerArc.Width = (InnerRadius + ArcThickness) * 2;
            outerArc.Height = (InnerRadius + ArcThickness) * 2;
            outerArc.ArcThickness = ArcThickness;
            outerArc.Stretch = Stretch.None;
            //根据当前的起始结束角度转换出当前圆弧的起止角度
            double Sa = StartAngel + OffsetAngle;
            double Ea = EndAngel + OffsetAngle;
            if (Sa > Ea)
            {
                outerArc.StartAngle = Ea;
                outerArc.EndAngle = Sa;
            }
            else
            {
                outerArc.StartAngle = Sa;
                outerArc.EndAngle = Ea;
            }
            outerArc.StrokeThickness = 0;
            outerArc.Fill = OuterColor;
            //计算并设置当前圆环的起点位置
            Canvas.SetLeft(outerArc, GetCenterPoint().X - (InnerRadius + ArcThickness));
            Canvas.SetTop(outerArc, GetCenterPoint().Y - (InnerRadius + ArcThickness));
            rootPanel.Children.Add(outerArc);
        }
        /// <summary>
        /// 绘制刻度线所在的圆弧
        /// </summary>
        private void DrawingScaleArcLine()
        {
            Arc scaleArc = new Arc();
            //圆弧大小根据当前设定的内圆半径而定
            scaleArc.Width = TempValue * 2;
            scaleArc.Height = TempValue * 2;
            scaleArc.ArcThickness = ArcThickness * 0.2;
            scaleArc.Stretch = Stretch.None;
            //根据当前的起始结束角度转换出当前圆弧的起止角度
            double Sa = StartAngel + OffsetAngle;
            double Ea = EndAngel + OffsetAngle;
            if (Sa > Ea)
            {
                scaleArc.StartAngle = Ea;
                scaleArc.EndAngle = Sa;
            }
            else
            {
                scaleArc.StartAngle = Sa;
                scaleArc.EndAngle = Ea;
            }
            scaleArc.StrokeThickness = 0;
            scaleArc.Fill = new SolidColorBrush(Colors.Gray);
            //计算并设置当前圆环的起点位置
            Canvas.SetLeft(scaleArc, GetCenterPoint().X - TempValue);
            Canvas.SetTop(scaleArc, GetCenterPoint().Y - TempValue);
            rootPanel.Children.Add(scaleArc);
        }
        #endregion
        #region 公共方法
        /// <summary>
        /// 获取单位刻度所占的角度
        /// </summary>
        /// <returns></returns>
        private double GetUnitAngel()
        {
            double scaleCount = GetScaleCount();
            double angelCount = Math.Abs(EndAngel - StartAngel);
            double unitAngel = angelCount / scaleCount;
            return unitAngel;
        }

        /// <summary>
        /// 获取刻度线总数
        /// </summary>
        /// <returns></returns>
        private double GetScaleCount()
        {
            return MaxValue - MinValue;
        }
        /// <summary>
        /// 获取坐标点
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetScaleLinePoint(double angel, double value)
        {
            Point center = GetCenterPoint();
            Point startPoint = new Point();
            angel = angel * Math.PI / 180;
            double X = center.X + value * Math.Cos(angel);
            double Y = center.Y + value * Math.Sin(angel);
            startPoint.X = X;
            startPoint.Y = Y;
            return startPoint;
        }

        /// <summary>
        /// 获取刻度线结束点
        /// </summary>
        /// <param name="angel"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private Point GetScaleLineEndPoint(double angel, double value, bool isLab = false)
        {
            double radius = TempValue + value;
            if (isLab || ScalePosition == ScalePosition.InnerArcIn || ScalePosition == ScalePosition.InnerArcOutSide)
            {
                radius = TempValue - value;
            }
            return GetScaleLinePoint(angel, radius);
        }

        /// <summary>
        /// 获取刻度线起始点
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetScaleLineStartPoint(double angel)
        {
            return GetScaleLinePoint(angel, TempValue);
        }

        /// <summary>
        /// 获取圆心坐标
        /// </summary>
        /// <returns></returns>
        private Point GetCenterPoint()
        {
            return new Point(InnerRadius + ArcThickness, InnerRadius + ArcThickness);
        }
        /// <summary>
        /// 根据最大最小值的设定 计算临界值
        /// </summary>
        private void CalculateCriticalPoint()
        {
            if (IntervalList != null && IntervalList.Count > 0)
            {
                //判断一下给的间隔点的值 确保间隔点的值在有效范围内
                IntervalList.RemoveAll(c => c.Value < MinValue || c.Value > MaxValue);
                IntervalList = IntervalList.OrderBy(c => c.Value).ToList();
                IntervalList[0].Value = IntervalList[0].Value > MinValue ? MinValue : IntervalList[0].Value;
                IntervalList[IntervalList.Count - 1].Value = IntervalList[IntervalList.Count - 1].Value < MaxValue ? MaxValue : IntervalList[IntervalList.Count - 1].Value;
            }
        }
        #endregion


        #endregion
    }
}
